﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using SolidWorks.Interop.sldworks;




namespace SolidWorksDll
{
    public class SolidWorksHelp
    {
        public static SldWorks swApp;

        public static void Test()
        {
            MessageBox.Show("测试成功");
        }

        //情况1 已经打开sw，直接获取
        //情况2 未打开sw，先打开再获取

        /// <summary>
        ///  获取已经打开的sw程序对象
        /// </summary>
        /// <returns>获取成功，返回true，否则false</returns>
        public static bool GetSwApp()
        {
            //错误1 swApp=new sldWorks()
            //错误2 swApp=CreateObject()
            try
            {
                if(false==CheckSwApp())
                {
                    return false;
                }
                //用户隔离的
                swApp = (SldWorks)Marshal.GetActiveObject("sldWorks.Application");
                return true; 
            }
            catch (Exception ex)
            {
                MessageBox.Show("请打开sw程序：" + ex.Message);
               
            }
            return false;
           //swApp =(SldWorks) Marshal.GetActiveObject("sldWorks.Application"); 
        }

        public static bool OpenSwApp()
        {
            if (false == CheckSwApp())
            {
                string swPath = GetSwAppPath();
                if ("" == swPath)
                {
                    return false;
                }

                Process p = StartSw(swPath);

                if (p == null)
                {
                    return false;
                }

                 Thread.Sleep(10*1000);
            }
            return GetFristSolidWorksRunningObject();
        }

        public static Process StartSw(string swPath)
        {
            //创建一个进程
            Process p = new Process();
            p.StartInfo.FileName = swPath;
            p.StartInfo.UseShellExecute = false;//是否使用操作系统shell启动
            p.StartInfo.RedirectStandardInput = false;//接受来自调用程序的输入信息
            p.StartInfo.RedirectStandardOutput = false;//由调用程序获取输出信息
            p.StartInfo.RedirectStandardError = false;//重定向标准错误输出
            p.StartInfo.CreateNoWindow = false;//不显示程序窗口

            p.Start();//启动程序

            //获取cmd窗口的输出信息
            //string output = p.StandardOutput.ReadToEnd();
            //等待程序执行完退出进程
            //p.WaitForExit();
            //p.Close();

            return p;
        }


        /// <summary>
        /// 获取SolidWorks安装路径。请注意，如果是64位操作系统和SolidWorks，必须将项目配置改为X64
        /// </summary>
        /// <returns></returns>
        public static string GetSwAppPath()
        {
            string swPath = "";
            RegistryKey regRootKey;
            regRootKey = Registry.ClassesRoot;

            for (int i = 99; i > 10; i--)
            {

                ///定义注册表子Path

                RegistryKey regKey;
                string strPath = @"SldWorks.Application." + i.ToString();

                regKey = regRootKey.OpenSubKey(strPath, RegistryKeyPermissionCheck.ReadSubTree);
                if (regKey == null)
                {
                    continue;
                }

                RegistryKey regSubKey;
                regSubKey = regKey.OpenSubKey("CLSID");

                if (regSubKey == null)
                {
                    continue;
                }

                string clsid = regSubKey.GetValue("").ToString();
                regSubKey.Close();
                regKey.Close();

                //通过clsid获取到路径

                strPath = @"CLSID\" + clsid;
                regKey = regRootKey.OpenSubKey(strPath, RegistryKeyPermissionCheck.ReadSubTree);
                if (regKey == null)
                {
                    continue;
                }
                //strPath = clsid;
                //RegistryKey regKey1 = regKey.OpenSubKey(strPath, RegistryKeyPermissionCheck.ReadSubTree);
                //if (regKey1 == null)
                //{
                //    continue;
                //}

                regSubKey = regKey.OpenSubKey("LocalServer32");
                if (regSubKey == null)
                {
                    continue;
                }
                string tt = regSubKey.GetValue("").ToString();
                if (tt != "")
                {
                    swPath = tt;
                    break;
                }


            }

            return swPath;

        }

        /// <summary>
        /// 检查SolidWorks进程是否存在，如果不存在，无需再获取对象
        /// </summary>
        /// <returns>存在返回true，否则返回false</returns>
        public static bool CheckSwApp()
        {
            Process[] processes = Process.GetProcessesByName("SLDWORKS");

            if (processes.Length == 0)
            {
                return false;
            }
            return true;
            //bool t = false;
            //int processID;
            //processID = processes[0].Id;
            //foreach (var item in processes)
            //{
            //    t = item.Responding;
            //    if (t == false)
            //    {
            //        processID = item.Id;
            //        break;
            //    }
            //}


        }
        
        
        [DllImport("ole32.dll")]
        public static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);

        [DllImport("ole32.dll")]
        public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);


        /// <summary>
        /// 用Hashtable来获取SolidWorks对象
        /// </summary>
        /// <returns>获取成功返回true，否则返回false</returns>
        public static bool GetFristSolidWorksRunningObject()
        {
            List<HasTableData> hasTableDatas = GetSolidWorksRunningObjectTable();
            if (hasTableDatas == null || hasTableDatas.Count == 0)
            {
                return false;
            }
            swApp = (SldWorks)hasTableDatas[0].Obj;
            return true;

        }

        public static List<HasTableData> GetSolidWorksRunningObjectTable()
        {
            Hashtable hashtables = GetAllRunningObjectTable();
            List<HasTableData> hasTableDatas = new List<HasTableData>();
            ICollection key = hashtables.Keys;

            foreach (string k in key)
            {
                string runningObjectName = k;
                string[] temp = runningObjectName.Split(new string[] { "_PID_" }, StringSplitOptions.None);
                if (temp[0].ToLower() == "SolidWorks")
                {

                    HasTableData hasTableData = new HasTableData
                    {
                        Name = runningObjectName,
                        Pid = Convert.ToInt32(temp[1]),
                        Obj = hashtables[k]
                    };
                    hasTableDatas.Add(hasTableData);
                }
            }

            return hasTableDatas;
        }

        public static Hashtable GetAllRunningObjectTable()
        {
            Hashtable result = new Hashtable();
            List<HasTableData> hasTableDatas = new List<HasTableData>();
            IntPtr numFetched = IntPtr.Zero;
            IRunningObjectTable runningObjectTable;
            IEnumMoniker monikerEnumerator;
            IMoniker[] monikers = new IMoniker[1];
            GetRunningObjectTable(0, out runningObjectTable);
            runningObjectTable.EnumRunning(out monikerEnumerator);
            monikerEnumerator.Reset();
            while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
            {
                IBindCtx ctx;
                CreateBindCtx(0, out ctx);
                string runningObjectName;
                monikers[0].GetDisplayName(ctx, null, out runningObjectName);

                runningObjectTable.GetObject(monikers[0], out object objReturnObject);
                result[runningObjectName] = objReturnObject;
            }
            return result;
        }

    }

    public class HasTableData
    {
        public string Name;
        public int Pid;
        public object Obj;

    }
}


